package com.seari.groovyrunner.utils;

import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.springframework.stereotype.Component;

import java.io.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * GroovyClassLoader动态加载Groovy Class
 */
@Component
public class GrooyUtils {

    public static GroovyClassLoader CLASS_LOADER = null;

    static {
//        CompilerConfiguration configuration = CompilerConfiguration.DEFAULT;
//        configuration.setSourceEncoding("UTF-8");
//        CLASS_LOADER = new GroovyClassLoader(GrooyUtils.class.getClassLoader(), configuration);
        CompilerConfiguration config = new CompilerConfiguration();
        config.setSourceEncoding("UTF-8");
        // 设置该GroovyClassLoader的父ClassLoader为当前线程的加载器(默认)
        CLASS_LOADER = new GroovyClassLoader(Thread.currentThread().getContextClassLoader(), config);
    }

    /**
     * groovy 脚本实现
     * @param connect
     * @param hostState
     * @param standbyState
     * @return true// 本地启动  false// 本地不启动
     */
    public static boolean checkProcess(String groovyPath,String method,int connect, int hostState, int standbyState) throws Exception {
        Map<String, Object> varMap=new HashMap<>();
        varMap.put("connect",connect);
        varMap.put("hostState",hostState);
        varMap.put("standbyState",standbyState);
        return (boolean)execute(groovyPath,method,varMap);
    }

    /**
     * @param groovyPath 脚本路径
     * @param object 脚本参数map
     * @return 脚本执行结果
     */
    public static Object execute(String groovyPath,String method, Object object) throws Exception {
        GroovyObject groovyObject = null;
        Object invokeResult=null;
        if (groovyPath==null){
            throw new FileNotFoundException(" not found groovyPath ! ");
        }
        File file = new File(groovyPath);
        if (!file.exists()){
            throw new FileNotFoundException(" not found groovy File ! ");
        }
        String scriptMd5 = MD5Utils.md5(readStringFromFile(file));
        synchronized (CLASS_LOADER){
            if (scriptMd5 == null) {
                groovyObject = (GroovyObject) CLASS_LOADER.parseClass(file).newInstance();
                CLASS_LOADER.clearCache();
            } else {
                Object o = GuavaCacheUtil.get(GuavaCacheUtil.GROOVY_OBJECT_MAP_KEY_PREFIX + groovyPath);
                Map<String, GroovyObject> map;
                if ("NULL".equals(o)) {
                    map=new HashMap();
                    groovyObject = (GroovyObject) CLASS_LOADER.parseClass(file).newInstance();
                    map.put(GuavaCacheUtil.GROOVY_OBJECT_KEY_PREFIX+scriptMd5,groovyObject);
                    GuavaCacheUtil.put(GuavaCacheUtil.GROOVY_OBJECT_MAP_KEY_PREFIX+groovyPath,map);
                }else{
                    map=(Map<String, GroovyObject>) o;
                    groovyObject = map.get(GuavaCacheUtil.GROOVY_OBJECT_KEY_PREFIX + scriptMd5);
                    if (groovyObject==null){
                        map.clear();
                        CLASS_LOADER.clearCache();
                        groovyObject = (GroovyObject) CLASS_LOADER.parseClass(file).newInstance();
                        map.put(GuavaCacheUtil.GROOVY_OBJECT_KEY_PREFIX+scriptMd5,groovyObject);
                        GuavaCacheUtil.put(GuavaCacheUtil.GROOVY_OBJECT_MAP_KEY_PREFIX+groovyPath,map);
                    }
                }
            }
        }
        invokeResult = groovyObject.invokeMethod(method, object);
        return invokeResult;
    }

    /**
     * @param groovyPath 脚本路径
     * @return 脚本执行结果
     */
    public static List<String> getGroovyMethod(String groovyPath) throws Exception {
        Class groovyClass = null;
        if (groovyPath==null){
            throw new FileNotFoundException(" not found groovyPath ! ");
        }
        File file = new File(groovyPath);
        if (!file.exists()){
            throw new FileNotFoundException(" not found groovy File ! ");
        }
        List<String> list=new ArrayList<>();
        groovyClass =  CLASS_LOADER.parseClass(file);
        CLASS_LOADER.clearCache();
        Method[] methods = groovyClass.getDeclaredMethods();
        for (Method method:methods) {
            if (method.toGenericString().startsWith("public")){
                list.add(method.getName());
            }
        }
        return list;
    }

    /**
     * @return 脚本执行结果
     */
    public static String checkGroovyScript(String content){
        String message ="success";
        try {
            CLASS_LOADER.parseClass(content);
            CLASS_LOADER.clearCache();
        } catch (Exception e) {
            message = e.getMessage();
        }
        return message;
    }

    public static String getFileMD5(File file){
        if (file.exists()){
            return  MD5Utils.md5(readStringFromFile(file));
        }else {
            return "";
        }
    }
    private static String readStringFromFile(File file) {
        InputStream in = null;
        ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
        try {
            in = new FileInputStream(file);
            int tempbyte;
            while ((tempbyte = in.read()) != -1) {
                outputStream.write(tempbyte);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (in!=null){
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return outputStream.toString();
    }
}
